package com.tang.provider;

import com.google.gson.Gson;
import com.tang.base.BaseRedis;
import com.tang.constant.Cons;
import com.tang.model.Order;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Map;
import java.util.UUID;

/**
 * Created by tangyifei on 2018/7/6.
 */
@Api(value = "micro-service-core-rabbitmq-producer", tags = {"micro-service-core-rabbitmq-producer"})
@Controller
public class RabbitMqProducer extends BaseRedis {

    private static final Logger logger = LogManager.getLogger(RabbitMqProducer.class);

    @ApiOperation(value = "测试消息", httpMethod = "POST", notes = "测试消息")
    @PostMapping("/rabbitmq/producer/{message}")
    public ResponseEntity<?> callbak(@PathVariable("message") @ApiParam(required = true, name = "message", value = "消息") String message) throws Exception {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        logger.info("消息的id是>>>>>>>>>>>>>>" + correlationData.getId());
        //用RabbitMQ发送MQTT需将exchange配置为amq.topic
        rabbitTemplate.convertAndSend(Cons.TOPIC_EXCHANGE_NAME, Cons.BASIC_ROUTING_KEY, message, correlationData);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    /**
     * 保存order , 同时需要向store服务发送通知减库存
     *
     * @param order
     * @return
     */
    @ApiOperation(value = "保存订单", httpMethod = "POST", notes = "保存订单")
    @PostMapping("/rabbitmq/producer")
    public ResponseEntity<?> saveOrder(@RequestBody @ApiParam(value = "json格式", name = "订单对象", required = true) Order order) throws Exception {
        logger.info("订单对象转化为字符串的形式为：>>>>>>>>>>>" + order.toString());
        Gson gson = new Gson();
        String json = gson.toJson(order);
        String msgId = UUID.randomUUID().toString();
        // 构建Message ,主要是使用 msgId 将 message 和 CorrelationData 关联起来。
        // 这样当消息发送到交换机失败的时候，在 MsgSendConfirmCallBack 中就可以根据
        // correlationData.getId()即 msgId,知道具体是哪个message发送失败,进而进行处理。
        // 将 msgId和 message绑定
        Message message = MessageBuilder.withBody(json.getBytes()).setContentEncoding("UTF-8")
                .setContentType(MessageProperties.CONTENT_TYPE_JSON).setCorrelationIdString(msgId).build();
        // 将 msgId和 CorrelationData绑定
        CorrelationData correlationData = new CorrelationData(msgId);
        // TODO 将 msgId 与 Message 的关系保存起来
        // 将 msgId 与 Message 的关系保存起来,例如放到缓存中.
        try {
            redisUtil.set(msgId, gson.fromJson(gson.toJson(message), Map.class));
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("缓存错误", e);
        }
        // 当 MsgSendReturnCallback回调时（消息从交换机到队列失败）,进行处理 {@code MsgSendReturnCallback}.
        // 当 MsgSendConfirmCallBack回调时,进行处理 {@code MsgSendConfirmCallBack}.
        // 定时检查这个绑定关系列表,如果发现一些已经超时(自己设定的超时时间)未被处理,则手动处理这些消息.

        // 发送消息
        // 指定消息交换机  "amq.topic"
        // 指定队列key    "direct.queue"
        rabbitTemplate.convertAndSend(Cons.TOPIC_EXCHANGE_NAME, Cons.OBJECT_ROUTING_KEY,
                message, correlationData);
        logger.info("发送的经过编码的消息是：" + message);
        return new ResponseEntity<>(HttpStatus.OK);
    }

}
